﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Bittorrent.Client.Peer;
using Bittorrent.Extentions;

namespace Bittorrent.Client.Tracker {
    public class HttpTrackerRequest {
        /// <summary>
        /// Gets or sets the announce URI.
        /// </summary>
        /// <value>The announce URI.</value>
        public Uri AnnounceUri { get; set; }

        /// <summary>
        /// Gets or sets the 20-byte hash of the info key from the torrent file.
        /// </summary>
        /// <value>The info hash.</value>
        public byte[] InfoHash { get; set; }

        /// <summary>
        /// Gets or sets the unique id for the client.
        /// </summary>
        /// <value>The peer id.</value>
        public PeerId PeerId { get; set; }

        /// <summary>
        /// Gets or sets the port number the client is listening on. Ports reserved for
        /// BitTorrent are typically 6881-6889. Beware that clients may choose to give
        /// up if it cannot establish a connection to a port within this range
        /// </summary>
        /// <value>The port.</value>
        public int Port { get; set; }

        /// <summary>
        /// Gets or sets the total amount uploaded (in bytes) since the client sent
        /// the Started RequestType.
        /// </summary>
        /// <value>The total amount uploaded in bytes.</value>
        public long Uploaded { get; set; }

        /// <summary>
        /// Gets or sets the total amount downloaded (in bytes) since the client sent
        /// the Started RequestType.
        /// </summary>
        /// <value>The total amount downloaded in bytes.</value>
        public long Downloaded { get; set; }

        /// <summary>
        /// Gets or sets the amount this client has left to download.
        /// </summary>
        /// <value>The amount left to download.</value>
        public long Left { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this client accepts a compact
        /// repsonse.
        /// </summary>
        /// <value><c>true</c> if compact reponse is supported; otherwise, <c>false</c>.</value>
        public bool Compact { get; set; }

        /// <summary>
        /// Gets or sets the request event type.
        /// </summary>
        /// <value>The request event.</value>
        public HttpTrackerRequestType RequestEvent { get; set; }

        /// <summary>
        /// Gets or sets the number of peers that the client wants to recive from
        /// the tracker.
        /// </summary>
        /// <value>The number of peers.</value>
        public int NumberOfPeers { get; set; }

        /// <summary>
        /// Gets or sets the tracker id, if a previous announce contained a tracker id, it
        /// should be set.
        /// </summary>
        /// <value>The tracker id.</value>
        public string TrackerId { get; set; }

        internal Uri GetRequestUri() {
            var uri = new UriBuilder(AnnounceUri);

            var query = new StringBuilder();

            query.Append(string.Format("info_hash={0}", HttpUtility.UrlEncode(InfoHash)));
            query.Append(string.Format("&peer_id={0}", HttpUtility.UrlEncode(PeerId.Bytes)));
            query.Append(string.Format("&port={0}", Port));
            query.Append(string.Format("&uploaded={0}", Uploaded));
            query.Append(string.Format("&downloaded={0}", Downloaded));
            query.Append(string.Format("&left={0}", Left));
            query.Append(string.Format("&compact={0}", Compact ? "1" : "0"));

            string eventString;
            switch (RequestEvent) {
                case HttpTrackerRequestType.Completed:
                    eventString = "completed";
                    break;
                case HttpTrackerRequestType.Started:
                    eventString = "started";
                    break;
                case HttpTrackerRequestType.Stopped:
                    eventString = "stopped";
                    break;
                case HttpTrackerRequestType.Non:
                default:
                    eventString = string.Empty;
                    break;
            }
            query.Append(string.Format("&event={0}", eventString));

            query.Append(string.Format("&numwant={0}", NumberOfPeers));

            // Optional
            if (!TrackerId.IsNullOrEmpty())
                query.Append(string.Format("&trackerid={0}", TrackerId));

            if (uri.Query.IsNullOrEmpty())
                uri.Query = query.ToString();
            else
                uri.Query = uri.Query.Substring(1) + "&" + query;

            return uri.Uri;
        }
    }
}
